几何类型 HXPoint / HXRect
UI 框架里打交道最多的就是坐标和矩形。HiEasyX 定义了一套简洁的几何类型,用来描述屏幕上的点、区域、大小。读完这一节,你就能轻松地算碰撞、算布局、算鼠标是不是点到了某个按钮里面。
基础类型别名
using HXGInt = int32_t; // 有符号坐标/尺寸
using HXGUInt = uint32_t; // 无符号计数/索引
信息
用 HXGInt 而不是裸 int,是为了保证在 32/64 位编译下尺寸一致,避免跨平台时的布局结构体大小漂移。写库代码建议统一用别名。
HXPoint:二维点
struct HXPoint {
HXGInt X;
HXGInt Y;
};
就这么简单,一个 X 一个 Y,表示屏幕上的位置。注意坐标系原点在 左上角,Y 向下增长,这是 Windows GUI 的惯例。
HXPoint pos{100, 200}; // 屏幕坐标 (100, 200)
pos.X += 50; // 向右移动 50 像素
HXRect:轴对齐矩形
struct HXRect {
HXGInt Left;
HXGInt Top;
HXGInt Right;
HXGInt Bottom;
};
HiEasyX 的矩形采用 左闭右开 的约定,也就是说:
- 包含
Left和Top边界 - 不包含
Right和Bottom边界
HXRect rc{0, 0, 100, 100}; // 宽 100,高 100,右下角像素是 (99, 99)
危险
很多新手会误以为 Right/Bottom 是最后一个像素的坐标。如果是那样,宽度应该是 Right - Left + 1。HiEasyX 用的是 右开区间,宽度直接 Right - Left 即可。这个约定和 Windows 的 RECT 以及很多 2D 图形 API 保持一致。
常用成员方法
判断点是否在矩形内
bool HXRect::PointInside(HXGInt x, HXGInt y) const;
bool HXRect::PointInside(const HXPoint& p) const;
HXRect button{100, 100, 200, 150};
HXPoint mouse{150, 120};
if (button.PointInside(mouse)) {
// 鼠标在按钮里面!
}
计算宽高
HXGInt HXRect::CalWidth() const; // Right - Left
HXGInt HXRect::CalHeight() const; // Bottom - Top
HXRect win{0, 0, 800, 600};
HXGInt w = win.CalWidth(); // 800
HXGInt h = win.CalHeight(); // 600
提示
写布局代码时,这两个方法出场率极高。比如把一个子控件居中:
HXRect parent{0, 0, 800, 600};
HXRect child{0, 0, 200, 100};
// 水平居中
child.Left = parent.Left + (parent.CalWidth() - child.CalWidth()) / 2;
child.Right = child.Left + child.CalWidth();
// 垂直居中
child.Top = parent.Top + (parent.CalHeight() - child.CalHeight()) / 2;
child.Bottom = child.Top + child.CalHeight();
常用几何运算示例
矩形位移
HXRect MoveRect(const HXRect& rc, HXGInt dx, HXGInt dy) {
return {rc.Left + dx, rc.Top + dy, rc.Right + dx, rc.Bottom + dy};
}
求两矩形交集
HXRect Intersect(const HXRect& a, const HXRect& b) {
HXRect out;
out.Left = std::max(a.Left, b.Left);
out.Top = std::max(a.Top, b.Top);
out.Right = std::min(a.Right, b.Right);
out.Bottom = std::min(a.Bottom, b.Bottom);
// 如果结果无效,宽高会是负数,调用方自行检查
return out;
}
求两矩形并集(最小包围盒)
HXRect Union(const HXRect& a, const HXRect& b) {
return {
std::min(a.Left, b.Left),
std::min(a.Top, b.Top),
std::max(a.Right, b.Right),
std::max(a.Bottom, b.Bottom)
};
}
矩形是否完全包含另一矩形
bool Contains(const HXRect& outer, const HXRect& inner) {
return outer.Left <= inner.Left &&
outer.Top <= inner.Top &&
outer.Right >= inner.Right &&
outer.Bottom >= inner.Bottom;
}
从点和大小构造矩形
HXRect MakeRect(HXGInt x, HXGInt y, HXGInt w, HXGInt h) {
return {x, y, x + w, y + h}; // 右开,所以直接加
}
// 用法
HXRect rc = MakeRect(10, 20, 300, 200); // {10, 20, 310, 220}
和 EasyX 的交互
EasyX 本身也有一套 POINT 和 RECT,但 HiEasyX 的几何类型是独立的。如果你需要混用,通常是在底层渲染或事件处理时做简单转换:
// HiEasyX → EasyX
POINT toEasyX(const HXPoint& p) { return {p.X, p.Y}; }
RECT toEasyX(const HXRect& r) { return {r.Left, r.Top, r.Right, r.Bottom}; }
// EasyX → HiEasyX
HXPoint fromEasyX(const POINT& p) { return {p.x, p.y}; }
HXRect fromEasyX(const RECT& r) { return {r.left, r.top, r.right, r.bottom}; }
信息
大部分情况下你不需要手动转。HiEasyX 的 Painter 和控件 API 内部已经消化掉了这些差异,只有在直接调用 EasyX 原生函数时才可能需要。
一句话总结
| 类型 | 用途 | 关键方法 |
|---|---|---|
HXPoint | 点坐标 | X, Y |
HXRect | 轴对齐矩形 | PointInside(), CalWidth(), CalHeight() |
提示
记住 左闭右开,矩形运算就不会翻车。CalWidth() == Right - Left,不包含右边界的那个像素,这和循环里写 for (int i = 0; i < n; ++i) 是一个道理。